home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / jmgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-01  |  29.6 KB  |  1,153 lines

  1. /* 
  2.  * jmgr.c --
  3.  *
  4.  *    Jukebox manager for the Jaquith archive system.
  5.  *
  6.  * Copyright 1991 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *
  15.  * Quote:
  16.  *      "My obsession: a life that shrivels up, slowly rots, goes soft as pulp.
  17.  *      This worry about decline grabs me by the throat as I awake.  In the
  18.  *      brief interval between dream and waking, it flaunts before my eyes
  19.  *      the frenzied dance of everything I would have liked to do, and never
  20.  *      will. As I turn over and over in my bed, the fear of the too late, of
  21.  *      the irreversible, propels me to the mirror to shave and get ready for
  22.  *      the day.  And that is the moment of truth.  The moment of the old
  23.  *      questions.  What am I today? Am I capable of renewel? What are the
  24.  *      chances I might still produce something I do not expect of myself?
  25.  *      For my life unfolds mainly in the yet to come, and is based on waiting.
  26.  *      Mine is a life of preparation.  I enjoy the present only insofar as it
  27.  *      is a promise of the future.  I am looking for the Promised Land and
  28.  *      listening to the music of my tomorrows.  My food is anticipation.
  29.  *      My drug is hope.''
  30.  *      -- Francois Jacob, ``The Statue Within: An Autobiography''
  31.  *
  32.  */
  33.  
  34. #ifndef lint
  35. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/jmgr.c,v 1.0 91/01/07 18:02:37 mottsmth Exp $ SPRITE (Berkeley)";
  36. #endif /* not lint */
  37.  
  38. #include "jaquith.h"
  39. #include "option.h"
  40. #include "jmgrInt.h"
  41.  
  42. Parms parms = {
  43.     DEF_DETAIL,
  44.     DEF_MGRLOG,
  45.     DEF_MGRPORT,
  46.     DEF_DEVFILE,
  47.     DEF_VOLFILE,
  48.     DEF_ROBOT,
  49.     DEF_SKIPLABEL
  50. };
  51.  
  52. Option optionArray[] = {
  53.     {OPT_INT, "logdetail", (char *)&parms.logDetail, "set logging detail (1 2 4 8)"},
  54.     {OPT_STRING, "logfile", (char *)&parms.logFile, "enable logging to file"},
  55.     {OPT_INT, "port", (char *)&parms.port, "port to listen on"},
  56.     {OPT_STRING, "devfile", (char *)&parms.devFile, "Device configuration file"},
  57.     {OPT_STRING, "volfile", (char *)&parms.volFile, "Volume configuration file"},
  58.     {OPT_STRING, "robot", (char *)&parms.robot, "Name of robot device"},
  59.     {OPT_TRUE, "reset", (char *)&parms.reset, "Reset device"},
  60.     {OPT_TRUE, "skiplabel", (char *)&parms.skipLabel, "Don't check volume label before use"}
  61. };
  62. int numOptions = sizeof(optionArray) / sizeof(Option);
  63.  
  64. /* File globals. */
  65. int syserr = 0;               /* Our personal record of errno */
  66. int jDebug;
  67. static char printBuf[T_MAXSTRINGLEN]; /* utility sprintf buffer */
  68. static SClient *clientList[MAXCLIENT];/* current-client array */
  69. static int clientMax = MAXCLIENT; /* size of client array */
  70. static SDev *devList;         /* our device list and... */
  71. static int deviceMax;         /* ...sizeof same */
  72. static Q_Handle *waitQ;       /* clients waiting for a volume */
  73. static int *volList;          /* list of known volumes */
  74. static Hash_Handle *volTab;   /* hash table of known volumes */
  75. static int robotStream;       /* I/O channel of robot arm */
  76. static FILE *memDbg;          /* stream for memory tracing */
  77.  
  78. /* The functions to be found here */
  79. static void     CheckParms      _ARGS_ ((Parms *parmsPtr));
  80. static SDev    *InitDevices     _ARGS_ ((char *filePtr));
  81. static int     *InitVolumes     _ARGS_ ((char *filePtr,
  82.                      Hash_Handle **hashTabPtr));
  83. static void     PerformLoop     _ARGS_ ((int sock));
  84. static int      ReadMsg         _ARGS_ ((SClient *clientPtr));
  85. static int      AddClient       _ARGS_ ((int sock));
  86. static void     DelClient       _ARGS_ ((SClient *clientPtr));
  87. static SClient *FindClientBySocket _ARGS_ ((int sock));
  88. static int      CheckAuth       _ARGS_ ((AuthHandle handle));
  89. static int      ProcessCmd      _ARGS_ ((SClient *clientPtr));
  90. static SDev    *FindFreeDevice  _ARGS_ ((int volId));
  91. static void     AssignDevice    _ARGS_ ((SClient *clientPtr,
  92.                      SDev *devPtr));
  93. static void     ReleaseDevice   _ARGS_ ((SClient *clientPtr));
  94. static int      SearchWaitQProc _ARGS_ ((Q_Handle *qPtr,
  95.                      Q_ClientData datum,
  96.                      int *retCode, int *callVal));
  97. static int      LoadVolume      _ARGS_ ((SDev *devPtr, int volId));
  98. static int      UnloadVolume    _ARGS_ ((SDev *devPtr));
  99. static int      AllocateVolume  _ARGS_ ((char *archive, int *volIdPtr));
  100. static int      ParseVolFile    _ARGS_ ((char *buf, int *volIDptr,
  101.                      int *locationPtr));
  102. static int      SendDevStatus   _ARGS_ ((int sock));
  103. static int      SendQStatusProc _ARGS_ ((Q_Handle *qPtr,
  104.                      Q_ClientData *datum,
  105.                      int *retCodePtr, int *callVal));
  106. static void     SigIntHandler   _ARGS_ ((int sig));
  107.  
  108.  
  109. /*
  110.  *----------------------------------------------------------------------
  111.  *
  112.  * main --
  113.  *
  114.  *    Jmgr is the physical manager for the archive device.
  115.  *
  116.  * The game plan:
  117.  *      Setup an array of descriptors for the devices we're managing.
  118.  *      Read in the initial mapping of volumes to devices.
  119.  *      Start accepting locking/unlocking requests for a particular volume.
  120.  *      If we can satisfy the request on a free device, do so.
  121.  *      Otherwise, enqueue the requestor.
  122.  *      When a device is released, the policy routine is run to
  123.  *      select the next client.  Currently this is FIFO.
  124.  *
  125.  * Results:
  126.  *    None.
  127.  *
  128.  * Side effects:
  129.  *    None.
  130.  *
  131.  *----------------------------------------------------------------------
  132.  */
  133.  
  134. void
  135. main(argc, argv)
  136.     int argc;                 /* main command line argument count */
  137.     char *argv[];             /* main command line arguments */
  138. {
  139.     int earSocket;
  140.     int i;
  141.  
  142. /*
  143.     memDbg = fopen("jmgr.mem","w");
  144.     MEM_CONTROL(8192, memDbg, TRACEMEM+TRACECALLS, 4096);
  145. */
  146.     for (i=0; i<clientMax; i++) {
  147.     clientList[i] = (SClient *)NULL;
  148.     }
  149.  
  150.     if (signal(SIGINT, SigIntHandler) == (void(*)()) -1) {
  151.     Utils_Bailout("signal", BAIL_PERROR);
  152.     }
  153.  
  154.     argc = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  155.  
  156.     CheckParms(&parms);
  157.     
  158.     if (Dev_InitRobot(parms.robot, &robotStream) != T_SUCCESS) {
  159.     sprintf(printBuf, "Couldn't init robot %s: errno = %d",
  160.         parms.robot, syserr);
  161.     Log_Event("Main", printBuf, LOG_FAIL);
  162.     exit(-1);
  163.     }
  164.  
  165.     waitQ = Q_Create("waitq", 0);
  166.  
  167.     devList = InitDevices(parms.devFile);
  168.  
  169.     volList = InitVolumes(parms.volFile, &volTab);
  170.  
  171.     earSocket = Sock_SetupEarSocket(&parms.port);
  172.  
  173.     Dev_DisplayMsg(robotStream, ACTIVE_MSG, MSG_STEADY);
  174.  
  175.     PerformLoop(earSocket); 
  176.  
  177.     exit(0);
  178. }
  179.  
  180.  
  181. /*
  182.  *----------------------------------------------------------------------
  183.  *
  184.  * InitDevices --
  185.  *
  186.  *    Initialize device table
  187.  *
  188.  * Results:
  189.  *    ptr to device table.
  190.  *
  191.  * Side effects:
  192.  *    Allocates array of SDev and updates global variable deviceMax
  193.  *
  194.  * See sample config file "devconfig" for data layout
  195.  *
  196.  *----------------------------------------------------------------------
  197.  */
  198.  
  199. static SDev *
  200. InitDevices(devFile)
  201.     char *devFile;            /* name of device configuration file */
  202. {
  203.     int i;
  204.     FILE *configFile;
  205.     SDev *tab;
  206.     int devCnt = 0;
  207.     int devStream;
  208.     int volId;
  209.     char volIdStr[T_MAXLINELEN];
  210.     DevConfig *itemPtr;
  211.     DevConfig *devList;
  212.  
  213.     Admin_ReadDevConfig(devFile, NULL, &devCnt);
  214.     devList = (DevConfig *)MEM_ALLOC("InitDevices",
  215.                      devCnt*sizeof(DevConfig));
  216.     if (Admin_ReadDevConfig(devFile, devList, &devCnt) != T_SUCCESS) {
  217.     sprintf(printBuf,"Can't read %s. errno %d\n", devFile, syserr);
  218.     Utils_Bailout(printBuf, BAIL_PRINT);
  219.     }
  220.  
  221.     tab = (SDev *)MEM_ALLOC("InitDevices", devCnt*sizeof(SDev));
  222.  
  223.     for (i=0,itemPtr=devList; i<devCnt; i++,itemPtr++) {
  224.     tab[i].skipCnt = 0;
  225.     tab[i].volId = NOVOLUME;
  226.     tab[i].clientPtr = (SClient *)NULL;
  227.     tab[i].location = itemPtr->location;
  228.     tab[i].name = Str_Dup(itemPtr->name);
  229.     /* Can't know what is in drive so ask */
  230.     sprintf(printBuf, "What volume is mounted in device %s? (-1 == none) ",
  231.         tab[i].name);
  232.     tab[i].volId = Utils_GetInteger(printBuf, -1, INT_MAX);
  233.     }
  234.  
  235.     MEM_FREE("InitDevices", devList);
  236.     deviceMax = devCnt; /* ugly global value */
  237.  
  238.     return (tab);
  239.     
  240. }
  241.  
  242.  
  243.  
  244. /*
  245.  *----------------------------------------------------------------------
  246.  *
  247.  * InitVolumes --
  248.  *
  249.  *    Initialize volume map
  250.  *
  251.  * Results:
  252.  *    ptr to volume map.
  253.  *
  254.  * Side effects:
  255.  *    Allocates array of int
  256.  *
  257.  * See sample config file "vconfig" for data layout.
  258.  * This file should be built by a utility that invokes
  259.  * the barcode reader on the jukebox.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263.  
  264. static int *
  265. InitVolumes(volFile, hashPtrPtr)
  266.     char *volFile;            /* name of volume configuration file */
  267.     Hash_Handle **hashPtrPtr; /* receiving hash table ptr */
  268. {
  269.     VolConfig *volList;
  270.     VolConfig *itemPtr;
  271.     int volCnt = -1;
  272.     Hash_Handle *hashPtr;
  273.     Hash_Handle *tmpHashPtr;
  274.     int i;
  275.  
  276.     Admin_ReadVolConfig(volFile, NULL, &volCnt);
  277.     volList = (VolConfig *)MEM_ALLOC("InitVolumes",
  278.                      volCnt*sizeof(VolConfig));
  279.     if (Admin_ReadVolConfig(volFile, volList, &volCnt) != T_SUCCESS) {
  280.     sprintf(printBuf,"Can't read %s. errno %d\n", volFile, syserr);
  281.     Utils_Bailout(printBuf, BAIL_PRINT);
  282.     }
  283.  
  284.     if ((hashPtr=Hash_Create("vol", 2*volCnt+1, Utils_StringHashProc, 0))
  285.     == NULL) {
  286.     Utils_Bailout("Couldn't create hash table1 for volume info\n",
  287.               BAIL_PRINT);
  288.     }
  289.     if ((tmpHashPtr=Hash_Create("loc", 2*volCnt+1, Utils_StringHashProc, 0))
  290.     == NULL) {
  291.     Utils_Bailout("Couldn't create hash table2 for volume info\n",
  292.               BAIL_PRINT);
  293.     }
  294.  
  295.     for (i=0,itemPtr=volList; i<volCnt; i++,itemPtr++) {
  296.     if (Hash_Insert(hashPtr, (char *)(&itemPtr->volId),
  297.             sizeof(itemPtr->volId),
  298.             (Hash_ClientData)itemPtr) != T_SUCCESS) {
  299.         sprintf(printBuf, "Duplicate volume '%d' in file %s?",
  300.             itemPtr->volId, volFile);
  301.         Utils_Bailout(printBuf, BAIL_PRINT);
  302.     }
  303.     if (Hash_Insert(tmpHashPtr, (char *)(&itemPtr->location),
  304.             sizeof(itemPtr->location),
  305.             (Hash_ClientData) 1) != T_SUCCESS) {
  306.         sprintf(printBuf, "Duplicate location '%d' in file %s?",
  307.             itemPtr->location, volFile);
  308.         Utils_Bailout(printBuf, BAIL_PRINT);
  309.     }
  310.     }
  311.  
  312.     Hash_Destroy(tmpHashPtr);
  313.     *hashPtrPtr = hashPtr;
  314.  
  315.     return T_SUCCESS;
  316. }
  317.  
  318.  
  319. /*
  320.  *----------------------------------------------------------------------
  321.  *
  322.  * CheckParms --
  323.  *
  324.  *    Validate parameters
  325.  *
  326.  * Results:
  327.  *    returns ptr to primary info block.
  328.  *
  329.  * Side effects:
  330.  *    None.
  331.  *
  332.  *----------------------------------------------------------------------
  333.  */
  334.  
  335. static void
  336. CheckParms(parmsPtr)
  337.     Parms *parmsPtr;          /* pointer to parameter block */
  338. {
  339.  
  340.     if ((parmsPtr->port <= 0) || (parmsPtr->port > MAXPORT)) {
  341.     Utils_Bailout("Checkparms: bad port number.\n", BAIL_PRINT);
  342.     }
  343.     if (parmsPtr->logFile != (char *)NULL) {
  344.     Log_Open(parmsPtr->logFile);
  345.     Log_SetDetail(parmsPtr->logDetail);
  346.     }
  347.     if (Utils_CheckName(parmsPtr->devFile, 1) != T_SUCCESS) {
  348.     Utils_Bailout("CheckParms: bad device file path.\n", BAIL_PRINT);
  349.     }
  350.     sprintf(printBuf,"Start. (port %d)\n", parmsPtr->port);
  351.     Log_Event("CheckParms", printBuf, LOG_MAJOR);
  352.  
  353. }
  354.  
  355.  
  356. /*
  357.  *----------------------------------------------------------------------
  358.  *
  359.  * PerformLoop --
  360.  *
  361.  *    Main command loop. We accept locking and unlocking requests
  362.  *      for the devices we're managing.
  363.  *
  364.  * Results:
  365.  *    None.
  366.  *
  367.  * Side effects:
  368.  *    Accepts connections from clients and handles command
  369.  * messages to and from them.
  370.  *
  371.  * Note:
  372.  *      The client holds the socket during the entire period from
  373.  * request to release so this limits our concurrency.
  374.  *
  375.  *----------------------------------------------------------------------
  376.  */
  377.  
  378. static void
  379. PerformLoop(earSocket)
  380.     int earSocket;            /* socket Number */
  381. {
  382.     int i;
  383.     int numReady;
  384.     int retCode;
  385.     int newSocket;
  386.     fd_set readSet;
  387.     fd_set copySet;
  388.     SClient *clientPtr;
  389.  
  390.     FD_ZERO(&readSet);
  391.     FD_SET(earSocket,&readSet);
  392.  
  393.     while(1) {
  394.     copySet = readSet;
  395.     numReady = select(FD_SETSIZE, ©Set, (fd_set *)NULL,
  396.               (fd_set *)NULL, (struct timeval *)NULL);
  397.     if (numReady == -1) {
  398.         continue;        /* shouldn't happen */
  399.     }
  400.     for (i=0; i<FD_SETSIZE; i++) {
  401.         if ((i == earSocket) && (FD_ISSET(i, ©Set))) {
  402.         newSocket = AddClient(earSocket);
  403.         FD_SET(newSocket, &readSet);
  404.         } else if (FD_ISSET(i, ©Set)) {
  405.         clientPtr = FindClientBySocket(i);
  406.         retCode = ReadMsg(clientPtr);
  407.         if (retCode == T_SUCCESS) {
  408.             retCode = ProcessCmd(clientPtr);
  409.         }
  410.         if (retCode != T_ACTIVE) {
  411.             FD_CLR(i, &readSet);
  412.             ReleaseDevice(clientPtr);
  413.             DelClient(clientPtr);
  414.         }
  415.         }
  416.     }
  417.     MEM_REPORT("PerformLoop", ALLROUTINES, SORTBYOWNER);
  418.     }
  419.  
  420. }
  421.  
  422.  
  423. /*
  424.  *----------------------------------------------------------------------
  425.  *
  426.  * ReadMsg --
  427.  *
  428.  *    Super simplistic msg reading. I haven't defined an complete
  429.  * message format. We're just expecting a userid followed by a
  430.  * cmd word (S_CMDLOCK, S_CMDFREE, etc.), and a volume number. 
  431.  * 
  432.  * Results:
  433.  *    None.
  434.  *
  435.  * Side effects:
  436.  *    None.
  437.  * 
  438.  *----------------------------------------------------------------------
  439.  */
  440.  
  441. static int
  442. ReadMsg(clientPtr)
  443.     SClient *clientPtr;       /* ptr to client */
  444. {
  445.     int sock = clientPtr->socket;
  446.  
  447.     if (Sock_ReadString(sock, &clientPtr->userName, 1) != T_SUCCESS) {
  448.     Log_Event("ReadMsg", "Couldn't read client name, client died.\n",
  449.           LOG_FAIL);
  450.     clientPtr->retCode = T_IOFAILED;
  451.     return T_FAILURE;
  452.     }
  453.  
  454.     if (Sock_ReadInteger(sock, &clientPtr->cmd) != T_SUCCESS) {
  455.     Log_Event("ReadMsg", "Couldn't read command, client died.\n",
  456.           LOG_FAIL);
  457.     clientPtr->retCode = T_IOFAILED;
  458.     return T_FAILURE;
  459.     }
  460.  
  461.     /* this may be junk for some command types */
  462.     if (Sock_ReadInteger(sock, &clientPtr->volId) != T_SUCCESS) {
  463.     Log_Event("ReadMsg", "Couldn't read volume id\n", LOG_FAIL);
  464.     clientPtr->retCode = T_IOFAILED;
  465.     return T_FAILURE;
  466.     }
  467.  
  468.     return T_SUCCESS;
  469.  
  470. }
  471.  
  472.  
  473. /*
  474.  *----------------------------------------------------------------------
  475.  *
  476.  * AddClient --
  477.  *
  478.  *    Accept an incoming connection request.
  479.  *
  480.  * Results:
  481.  *    Returns updated readSet and descriptor count for select.
  482.  *
  483.  * Side effects:
  484.  *    None.
  485.  *
  486.  *----------------------------------------------------------------------
  487.  */
  488.  
  489. static int
  490. AddClient(earSocket)
  491.     int earSocket;            /* socket number */
  492. {
  493.     int newSocket;
  494.     struct sockaddr_in newName;
  495.     int nameLen = sizeof(struct sockaddr_in);
  496.     struct hostent *peerInfo;
  497.     SClient *clientPtr;
  498.     int hostLen;
  499.     int i;
  500.  
  501.     if ((newSocket=accept(earSocket, &newName, &nameLen)) == -1) {
  502.     sprintf(printBuf,"accept failed: %s", sys_errlist[errno]);
  503.     Log_Event("AddClient", printBuf, LOG_FAIL);
  504.     }
  505.     if ((peerInfo=gethostbyaddr((char *)&newName.sin_addr,
  506.                 nameLen, AF_INET)) == NULL) {
  507.     sprintf(printBuf,"gethostbyaddr failed: %s", sys_errlist[errno]);
  508.     Log_Event("AddClient", printBuf, LOG_FAIL);
  509.     }
  510.     hostLen = strlen(peerInfo->h_name) + 1;
  511.     clientPtr =    (SClient *)MEM_ALLOC("AddClient", sizeof(SClient)+hostLen);
  512.     clientPtr->volId = NOVOLUME;
  513.     clientPtr->devPtr = (SDev *)NULL;
  514.     clientPtr->socket = newSocket;
  515.     clientPtr->hostName = Str_Dup(peerInfo->h_name);
  516.  
  517.     /* Allocate a table location for the guy ... */
  518.     for (i=0; i<clientMax; i++) {
  519.     if (clientList[i] == (SClient *)NULL) break;
  520.     }
  521.     if (i == clientMax) {
  522.     Log_Event("AddClient", "Client table is full\n", LOG_FAIL);
  523.     }
  524.     clientList[i] = clientPtr;
  525.     clientPtr->indx = i;
  526.     sprintf(printBuf, "Connection from %s on socket %d, index %d\n",
  527.         clientPtr->hostName, newSocket, i);
  528.     Log_Event("AddClient", printBuf, LOG_MAJOR);
  529.  
  530.     return(newSocket);
  531.  
  532. }
  533.  
  534.  
  535. /*
  536.  *----------------------------------------------------------------------
  537.  *
  538.  * ProcessCmd --
  539.  *
  540.  *    Handle the client request.
  541.  *      We do S_CMD{NULL,LOCK,FREE,STAT} at the moment.
  542.  *
  543.  * For lock requests we (eventually) return the device name as a string.
  544.  * For unlock requests we just return T_SUCCESS.
  545.  *
  546.  * Results:
  547.  *    status.
  548.  *
  549.  * Side effects:
  550.  *    Either a success message, or an en-fattened queue.
  551.  *
  552.  *----------------------------------------------------------------------
  553.  */
  554.  
  555. static int
  556. ProcessCmd(clientPtr)
  557.     SClient *clientPtr;       /* ptr to client */
  558. {
  559.     int status = T_FAILURE;
  560.     int volId = clientPtr->volId;
  561.     int cmd = clientPtr->cmd;
  562.     SDev *devPtr;
  563.     
  564.     sprintf(printBuf, "Cmd %d vol %d\n", cmd, volId);
  565.     Log_Event("ProcessCmd", printBuf, LOG_MAJOR);
  566.  
  567.     switch(cmd) {
  568.     /*
  569.      * Do nothing
  570.      */
  571.     case S_CMDNULL: 
  572.     clientPtr->retCode = T_SUCCESS;
  573.     break;
  574.     /*
  575.      * Request a volume
  576.      */
  577.     case S_CMDLOCK: 
  578.     if (clientPtr->devPtr != (SDev *)NULL) {
  579.         clientPtr->retCode = T_BADCMD;
  580.     } else {
  581.         clientPtr->retCode = T_SUCCESS;
  582.         status = T_ACTIVE;
  583.         devPtr = FindFreeDevice(volId);
  584.         if (devPtr != (SDev *)NULL) {
  585.         AssignDevice(clientPtr, devPtr);
  586.         } else {
  587.         sprintf(printBuf, "Enqueue 0x%x index %d for volume %d\n",
  588.             clientPtr, clientPtr->indx, volId);
  589.         Log_Event("ProcessCmd", printBuf, LOG_MINOR);
  590.         Q_Add(waitQ, (Q_ClientData)clientPtr, Q_TAILQ);
  591.         }
  592.     }
  593.     break;
  594.     /*
  595.      * Done. release volume.
  596.      */
  597.     case S_CMDFREE:
  598.     devPtr = clientPtr->devPtr;
  599.     if (devPtr == (SDev *)NULL) {
  600.         clientPtr->retCode = T_BADCMD;
  601.     } else if ((devPtr->volId != volId) ||
  602.            (devPtr->clientPtr != clientPtr)) {
  603.         clientPtr->retCode = T_BADCMD;
  604.     } else {
  605.         clientPtr->retCode = T_SUCCESS;
  606.     }
  607.     break;
  608.  
  609.     case S_CMDSTAT:
  610.     Sock_WriteInteger(clientPtr->socket, T_SUCCESS);
  611.     SendDevStatus(clientPtr->socket);
  612.     status = Q_Count(waitQ);
  613.     Sock_WriteInteger(clientPtr->socket, status);
  614.     Q_Iterate(waitQ, SendQStatusProc, (int *)clientPtr->socket);
  615.     break;
  616.  
  617.     default:
  618.     clientPtr->retCode = T_BADCMD;
  619.     break;
  620.     }
  621.  
  622.     return status;
  623. }
  624.  
  625.  
  626. /*
  627.  *----------------------------------------------------------------------
  628.  *
  629.  * AssignDevice --
  630.  *
  631.  *    Assign a device to a client.
  632.  *
  633.  * Results:
  634.  *    None.
  635.  *
  636.  * Side effects:
  637.  *      We send a response message to the client.
  638.  *
  639.  *----------------------------------------------------------------------
  640.  */
  641.  
  642. static void
  643. AssignDevice(clientPtr, devPtr)
  644.     SClient *clientPtr;       /* ptr to client */
  645.     SDev *devPtr;             /* assigned device */
  646. {
  647.     int sock = clientPtr->socket;
  648.     int volId = clientPtr->volId;
  649.  
  650.     sprintf(printBuf, "Assigning 0x%x index %d vol %d to device %s\n",
  651.         clientPtr, clientPtr->indx, clientPtr->volId,
  652.         devPtr->name);
  653.     Log_Event("AssignDevice", printBuf, LOG_MINOR);
  654.  
  655.     if (devPtr->volId != volId) {
  656.     if (devPtr->volId != NOVOLUME) {
  657.         if (UnloadVolume(devPtr) != T_SUCCESS) {
  658.         Sock_WriteInteger(sock, T_ROBOTFAILED);
  659.         return;
  660.         }
  661.     }
  662.     if (LoadVolume(devPtr, volId) != T_SUCCESS) {
  663.         Sock_WriteInteger(sock, T_ROBOTFAILED);
  664.         return;
  665.     }
  666.     }
  667.  
  668.     volId = clientPtr->volId;
  669.     devPtr->clientPtr = clientPtr;
  670.     clientPtr->devPtr = devPtr;
  671.  
  672.     Sock_WriteInteger(sock, T_SUCCESS);
  673.     Sock_WriteString(sock, devPtr->name, 0);
  674.  
  675. }
  676.  
  677.  
  678. /*
  679.  *----------------------------------------------------------------------
  680.  *
  681.  * ReleaseDevice --
  682.  *
  683.  *    Relinquish a device and give it to a waiting client.
  684.  *
  685.  * Results:
  686.  *    None.
  687.  *
  688.  * Side effects:
  689.  *    The policy mechanism is invoked to select a waiting client.
  690.  *
  691.  *----------------------------------------------------------------------
  692.  */
  693.  
  694. static void
  695. ReleaseDevice(clientPtr)
  696.     SClient *clientPtr;       /* ptr to client */
  697. {
  698.     SDev *devPtr = clientPtr->devPtr;
  699.  
  700.     if (devPtr != (SDev *)NULL) {
  701.     sprintf(printBuf, "Client 0x%x releasing vol %d device %s\n",
  702.         clientPtr, devPtr->volId, devPtr->name);
  703.     Log_Event("ReleaseDevice", printBuf, LOG_MINOR);
  704.     devPtr->clientPtr = NULL;
  705.     if (Q_Count(waitQ) > 0) {
  706.         clientPtr = (SClient *)Q_Iterate(waitQ, SearchWaitQProc, (int *)0);
  707.         if (clientPtr != (SClient *)NULL) {
  708.         AssignDevice(clientPtr, devPtr);
  709.         }
  710.     }
  711.     } else {
  712.     sprintf(printBuf, "Client 0x%x. No device to release\n", clientPtr);
  713.     Log_Event("ReleaseDevice", printBuf, LOG_MINOR);
  714.     }
  715.  
  716.  
  717. }
  718.  
  719.  
  720. /*
  721.  *----------------------------------------------------------------------
  722.  *
  723.  * SearchWaitQProc --
  724.  *
  725.  *    Callback function implementing waiting queue search policy
  726.  *
  727.  * Results:
  728.  *    client ptr.
  729.  *
  730.  * Side effects:
  731.  *    None.
  732.  *
  733.  * Note:
  734.  *      This is used indirectly by the SelectClient procedure.
  735.  *
  736.  *----------------------------------------------------------------------
  737.  */
  738.  
  739. static int
  740. SearchWaitQProc(qPtr, datum, retCodePtr, callVal)
  741.     Q_Handle *qPtr;            /* wait queue */
  742.     Q_ClientData datum;       /* client structure */
  743.     int *retCodePtr;          /* receiving return code location */
  744.     int *callVal;             /* unused */
  745. {
  746.     SClient *clientPtr = (SClient *)datum;
  747.     SDev *devPtr;
  748.  
  749.     sprintf(printBuf, "Considering 0x%x for vol %d\n",
  750.         clientPtr, clientPtr->volId);
  751.     Log_Event("SearchWaitQProc", printBuf, LOG_MINOR);
  752.     if ((devPtr=FindFreeDevice(clientPtr->volId)) == NULL) {
  753.     *retCodePtr = (int)NULL;
  754.     return Q_ITER_CONTINUE;
  755.     } else {
  756.     clientPtr->devPtr = devPtr;
  757.     *retCodePtr = (int)clientPtr;
  758.     return Q_ITER_REMOVE_STOP;
  759.     }
  760.  
  761. }
  762.  
  763.  
  764.  
  765. /*
  766.  *----------------------------------------------------------------------
  767.  *
  768.  * FindFreeDevice --
  769.  *
  770.  *    Locate an idle device
  771.  *
  772.  * Results:
  773.  *    device ptr.
  774.  *
  775.  * Side effects:
  776.  *    None.
  777.  *
  778.  * Note:
  779.  *      If a device is free but the desired volume is mounted in
  780.  *      a busy device then a busy status is returned.
  781.  *
  782.  *----------------------------------------------------------------------
  783.  */
  784.  
  785. static SDev *
  786. FindFreeDevice(volId)
  787.     int volId;                /* volume Id desired */
  788. {
  789.     int i;
  790.     SDev *devPtr;
  791.  
  792.     for (i=0; i<deviceMax; i++) {
  793.     if (devList[i].volId == volId) {
  794.         if (devList[i].clientPtr == (SClient *)NULL) {
  795.         sprintf(printBuf, "Found vol %d avail in drive %s\n",
  796.             volId, devList[i].name);
  797.         Log_Event("FindFreeDevice", printBuf, LOG_MINOR);
  798.         return devList+i;
  799.         } else {
  800.         sprintf(printBuf, "Found vol %d but drive %s is in use\n",
  801.             volId, devList[i].name);
  802.         Log_Event("FindFreeDevice", printBuf, LOG_MINOR);
  803.         return (SDev *)NULL;
  804.         }
  805.     }
  806.     }
  807.  
  808.     for (i=0; i<deviceMax; i++) {
  809.     if (devList[i].volId == NOVOLUME) {
  810.         sprintf(printBuf, "Found empty device %s\n", devList[i].name);
  811.         Log_Event("FindFreeDevice", printBuf, LOG_MINOR);
  812.             return devList+i;
  813.     }
  814.     }
  815.  
  816.     for (i=0; i<deviceMax; i++) {
  817.     if (devList[i].clientPtr == (SClient *)NULL) {
  818.         sprintf(printBuf, "Found idle device %s\n", devList[i].name);
  819.         Log_Event("FindFreeDevice", printBuf, LOG_MINOR);
  820.         return devList+i;
  821.     }
  822.     }
  823.  
  824.     return (SDev *)NULL;
  825.  
  826. }
  827.  
  828.  
  829. /*
  830.  *----------------------------------------------------------------------
  831.  *
  832.  * LoadVolume --
  833.  *
  834.  *    Issue commands to move a volume into specified device.
  835.  *
  836.  * Results:
  837.  *    None.
  838.  *
  839.  * Side effects:
  840.  *    Robot is probably activated.
  841.  *
  842.  *----------------------------------------------------------------------
  843.  */
  844.  
  845. static int
  846. LoadVolume(devPtr, volId)
  847.     SDev *devPtr;             /* receiving device */
  848.     int volId;                /* identifier of volume to be loaded */
  849. {
  850.     int homeLoc;
  851.     VolConfig *volPtr;
  852.     int retCode;
  853.     int chkId;
  854.     char volLabel[T_MAXLABELLEN];
  855.  
  856.     if (Hash_Lookup(volTab, (char *)&volId, sizeof(volPtr->volId),
  857.             (Hash_ClientData *)&volPtr) != T_SUCCESS) {
  858.     sprintf(printBuf, "Unknown volume %d specified.\n", volId);
  859.     Log_Event("LoadVolume", printBuf, LOG_FAIL);
  860.     return T_FAILURE;
  861.     }
  862.  
  863.     homeLoc = volPtr->location;
  864.     devPtr->volId = volId;
  865.  
  866.     sprintf(printBuf, "Loading %d into %s from location %d\n",
  867.         volId, devPtr->name, homeLoc);
  868.     Log_Event("LoadVolume", printBuf, LOG_MINOR);
  869.     
  870.     if (!parms.skipLabel) {
  871.     if (Dev_ReadVolLabel(robotStream, homeLoc, volLabel, &chkId) != T_SUCCESS) {
  872.         sprintf(printBuf, "Couldn't read volume label in slot %d. Continuing.\n",
  873.             homeLoc);
  874.         Log_Event("LoadVolume", printBuf, LOG_FAIL);
  875.     } else if (chkId != volId) {
  876.         sprintf(printBuf, "Found volId %d (\"%s\") in slot %d but expected %d. Load aborted.\n",
  877.             chkId, volLabel, homeLoc, volId);
  878.         Log_Event("LoadVolume", printBuf, LOG_FAIL);
  879.         return T_ROBOTFAILED;
  880.     }
  881.     }
  882.     retCode = Dev_MoveVolume(robotStream, homeLoc, devPtr->location);
  883.  
  884.     return retCode;
  885. }
  886.  
  887.  
  888. /*
  889.  *----------------------------------------------------------------------
  890.  *
  891.  * UnloadVolume --
  892.  *
  893.  *    Issue commands necessary to move a volume from specified device.
  894.  *
  895.  * Results:
  896.  *    None.
  897.  *
  898.  * Side effects:
  899.  *    Robot is activated.
  900.  *
  901.  *----------------------------------------------------------------------
  902.  */
  903.  
  904. static int
  905. UnloadVolume(devPtr)
  906.     SDev *devPtr;             /* source device */
  907. {
  908.     int volId = devPtr->volId;
  909.     VolConfig *volPtr;
  910.     int homeLoc;
  911.     int retCode;
  912.  
  913.     if (Hash_Lookup(volTab, (char *)&volId, sizeof(volPtr->volId),
  914.             (Hash_ClientData *)&volPtr) != T_SUCCESS) {
  915.     sprintf(printBuf, "Unknown volume %d specified.\n", volId);
  916.     Log_Event("UnloadVolume", printBuf, LOG_FAIL);
  917.     return T_FAILURE;
  918.     }
  919.  
  920.     homeLoc = volPtr->location;
  921.     devPtr->volId = NOVOLUME;
  922.  
  923.     sprintf(printBuf, "Unloading %d from %s to location %d\n",
  924.         volId, devPtr->name, homeLoc);
  925.     Log_Event("UnloadVolume", printBuf, LOG_MINOR);
  926.  
  927.     if ((retCode=Dev_UnloadVolume(devPtr->name)) != T_SUCCESS) {
  928.     sprintf(printBuf, "Couldn't unload device %s: errno %d",
  929.         devPtr->name, errno);
  930.     Log_Event("UnloadVolume", printBuf, LOG_FAIL);
  931.     } else {
  932.     retCode = Dev_MoveVolume(robotStream, devPtr->location, homeLoc);
  933.     }
  934.  
  935.     return retCode;
  936. }
  937.  
  938.  
  939. /*
  940.  *----------------------------------------------------------------------
  941.  *
  942.  * SendDevStatus --
  943.  *
  944.  *    Return current state of device affairs.
  945.  *
  946.  * Results:
  947.  *    status.
  948.  *
  949.  * Side effects:
  950.  *      We send a device summary
  951.  *
  952.  *----------------------------------------------------------------------
  953.  */
  954.  
  955. static int
  956. SendDevStatus(sock)
  957.     int sock;                 /* socket to ship summary to */
  958. {
  959.     int i;
  960.  
  961.     /*
  962.      * Must adhere to S_DevStat layout even though
  963.      * we're not actually using the structure
  964.      */
  965.     Sock_WriteInteger(sock, deviceMax);
  966.     for (i=0; i<deviceMax; i++) {
  967.     Sock_WriteString(sock, devList[i].name, 0);
  968.     Sock_WriteInteger(sock, devList[i].volId);
  969.     if (devList[i].clientPtr == (SClient *)NULL) {
  970.         Sock_WriteString(sock, "", 0);
  971.         Sock_WriteString(sock, "", 0);
  972.     } else {
  973.         Sock_WriteString(sock, devList[i].clientPtr->hostName, 0);
  974.         Sock_WriteString(sock, devList[i].clientPtr->userName, 0);
  975.     }
  976.     }
  977.  
  978.     return T_SUCCESS;
  979. }
  980.  
  981.  
  982.  
  983. /*
  984.  *----------------------------------------------------------------------
  985.  *
  986.  * SendQStatusProc --
  987.  *
  988.  *    Send client's info
  989.  *
  990.  * Results:
  991.  *    iteration status for Q_Iterate routine.
  992.  *
  993.  * Side effects:
  994.  *    We send the status of each Q member
  995.  *
  996.  * Note:
  997.  *      This is a callback routine used by Q_Iterate
  998.  *
  999.  *----------------------------------------------------------------------
  1000.  */
  1001.  
  1002. static int
  1003. SendQStatusProc(qPtr, datum, retCodePtr, callVal)
  1004.     Q_Handle *qPtr;            /* q identifier */
  1005.     Q_ClientData datum;       /* ptr to client */
  1006.     int *retCodePtr;          /* receiving return code location */
  1007.     int *callVal;             /* sock to write to */
  1008. {
  1009.     SClient *clientPtr = (SClient *)datum;
  1010.     int sock = (int)callVal;
  1011.  
  1012.     /*
  1013.      * Must adhere to S_QStat layout even though
  1014.      * we're not actually using the structure
  1015.      * (The 'count' field has been sent already).
  1016.      */
  1017.     Sock_WriteInteger(sock, clientPtr->volId);
  1018.     Sock_WriteString(sock, clientPtr->hostName, 0);
  1019.     Sock_WriteString(sock, clientPtr->userName, 0);
  1020.  
  1021.     return Q_ITER_CONTINUE;
  1022. }
  1023.  
  1024.  
  1025. /*
  1026.  *----------------------------------------------------------------------
  1027.  *
  1028.  * DelClient --
  1029.  *
  1030.  *    Exorcise a client from list.
  1031.  *
  1032.  * Results:
  1033.  *    
  1034.  *
  1035.  * Side effects:
  1036.  *    We send a message telling the client what happened.
  1037.  *
  1038.  *----------------------------------------------------------------------
  1039.  */
  1040.  
  1041. static void
  1042. DelClient(clientPtr)
  1043.     SClient *clientPtr;       /* ptr to client */
  1044. {
  1045.     int sock = clientPtr->socket;
  1046.     int indx = clientPtr->indx;
  1047.     int retCode = clientPtr->retCode;
  1048.  
  1049.     sprintf(printBuf,"index %d sock %d\n", indx, sock);
  1050.     Log_Event("DelClient", printBuf, LOG_TRACE);
  1051.  
  1052.     Sock_WriteInteger(sock, retCode);
  1053.     close(sock);
  1054.  
  1055.     MEM_FREE("DelClient", (char *)clientPtr->hostName);
  1056.     MEM_FREE("DelClient", (char *)clientPtr->userName);
  1057.     MEM_FREE("DelClient", (char *)clientPtr);
  1058.     clientList[indx] = (SClient *)NULL;
  1059.  
  1060. }
  1061.  
  1062.  
  1063. /*
  1064.  *----------------------------------------------------------------------
  1065.  *
  1066.  * FindClientBySocket --
  1067.  *
  1068.  *    Locate a client by socket.
  1069.  *
  1070.  * Results:
  1071.  *    Ptr to client or NULL;
  1072.  *
  1073.  * Side effects:
  1074.  *    None.
  1075.  *
  1076.  *----------------------------------------------------------------------
  1077.  */
  1078.  
  1079. static SClient *
  1080. FindClientBySocket(sock)
  1081.     int sock;                 /* socket number */
  1082. {
  1083.     int i;
  1084.  
  1085.     for (i=0; i<MAXCLIENT; i++) {
  1086.     if ((clientList[i] != (SClient *)NULL) &&
  1087.         (clientList[i]->socket == sock)) {
  1088.         sprintf(printBuf,"Found socket %d, index %d\n", sock, i);
  1089.         Log_Event("FindClientBySocket", printBuf, LOG_TRACE);
  1090.         return clientList[i];
  1091.     }
  1092.     }
  1093.  
  1094.     sprintf(printBuf,"Failed to find sock %d\n", sock);
  1095.     Log_Event("FindClientBySocket", printBuf, LOG_FAIL);
  1096.  
  1097.     return ((SClient *)NULL);
  1098.  
  1099. }
  1100.  
  1101.  
  1102. /*
  1103.  *----------------------------------------------------------------------
  1104.  *
  1105.  * CheckAuth --
  1106.  *
  1107.  *    Check a client's authorization ticket.
  1108.  *      Will use Kerberos eventually.
  1109.  *
  1110.  * Results:
  1111.  *     0 == ok; 1 == unauthorized.
  1112.  *
  1113.  * Side effects:
  1114.  *    None.
  1115.  *
  1116.  *----------------------------------------------------------------------
  1117.  */
  1118.  
  1119. static int
  1120. CheckAuth(ticket)
  1121.     AuthHandle ticket;        /* kerberos ticket */
  1122. {
  1123.     return T_SUCCESS;
  1124.  
  1125. }
  1126.  
  1127.  
  1128. /*
  1129.  *----------------------------------------------------------------------
  1130.  *
  1131.  * SigIntHandler
  1132.  *
  1133.  *    Catch SIGINT interrupts.
  1134.  *
  1135.  * Results:
  1136.  *    none.
  1137.  *
  1138.  * Side effects:
  1139.  *    Kills program
  1140.  *
  1141.  *----------------------------------------------------------------------
  1142.  */
  1143.  
  1144. static void
  1145. SigIntHandler(signal)
  1146.     int signal;               /* signal type */
  1147. {
  1148.     if (robotStream != -1) {
  1149.     Dev_DisplayMsg(robotStream, READY_MSG, MSG_STEADY);
  1150.     }
  1151.     exit(-1);
  1152. }
  1153.